package com.example.yyy

import android.content.Context
import android.content.SharedPreferences
import java.io.*
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

class Preference<T>(val context: Context,val name:String,val default:T) :ReadWriteProperty<Any?,T> {

    /**
     * 通过属性代理初始化共享参数对象
     */
    val prefs:SharedPreferences by lazy {
        context.getSharedPreferences("default",Context.MODE_PRIVATE)

    }

    /**
     * 接管属性值的获取行为
     */
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return findPreference(name,default)
    }

    /**
     * 接管属性值的修改行为
     */
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
       return putPreference(name,value)
    }

    /**
     * 利用with函数定义临时的命名空间
     * 查找数据 返回给调用方法一个具体的对象
     * 如果查找不到类型就采用反序列化方法来返回类型
     * default是默认对象 以防止会返回空对象的异常
     * 即如果name没有查找到value 就返回默认的序列化对象，然后经过反序列化返回
     */
    private fun<A> findPreference(name: String,default:A): A = with(
        prefs){
        val res:Any?= when(default){
            is Long ->getLong(name,default)
            is String -> getString(name,default)
            is Int -> getInt(name,default)
            is Boolean -> getBoolean(name,default)
            is Float -> getFloat(name,default)
            else -> deSerialization(getString(name,serialize(default))!!)
        }
        res as A
    }

    private fun<A> putPreference(name: String,value:A) = with(
        prefs.edit()){
       when (value){
            is Long ->putLong(name,value)
            is String -> putString(name,value)
            is Int -> putInt(name,value)
            is Boolean ->putBoolean(name,value)
            is Float -> putFloat(name,value)
            else -> putString(name,serialize(value))
        }.apply()
//        res as A
    }

    /**
     * 删除全部数据
     */
    fun clearPreference(){
        prefs.edit().clear().commit()
    }

    /**
     * 根据key删除存储数据
     */
    fun clearPreference(key:String){
        prefs.edit().remove(key).commit()
    }

    /**
     * 序列化对象
     * @param obj default:A
     * @return String
     * @throws IOException
     */
    @Throws(IOException::class)
    private fun<A> serialize(obj:A):String{
        val byteArrayOutputStream = ByteArrayOutputStream()
        val objectOutputStream = ObjectOutputStream(byteArrayOutputStream)
        objectOutputStream.writeObject(obj)
        var setStr = byteArrayOutputStream.toString("ISO-8859-1")
        setStr=java.net.URLEncoder.encode(setStr,"UTF-8")
        objectOutputStream.close()
        byteArrayOutputStream.close()
        return setStr
    }

    /**
     * 反序列化对象
     * @param str
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @Throws(IOException::class, ClassNotFoundException::class)
    private fun<A> deSerialization(str: String): A {
        val redStr = java.net.URLDecoder.decode(str, "UTF-8")
        val byteArrayInputStream = ByteArrayInputStream(
            redStr.toByteArray(charset("ISO-8859-1")))
        val objectInputStream = ObjectInputStream(
            byteArrayInputStream)
        val obj = objectInputStream.readObject() as A
        objectInputStream.close()
        byteArrayInputStream.close()
        return obj
    }
}